package com.zto.tbschedule.console.service.impl;

import com.zto.tbschedule.console.tbschedule.*;
import org.apache.zookeeper.CreateMode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import com.zto.tbschedule.console.mapper.ApplicationBackModelMapper;
import com.zto.tbschedule.console.mapper.ApplicationModelMapper;
import com.zto.tbschedule.console.model.ApplicationBackModel;
import com.zto.tbschedule.console.model.ApplicationBackModelExample;
import com.zto.tbschedule.console.model.ApplicationModel;
import com.zto.tbschedule.console.service.IScheduleService;
import com.zto.tbschedule.console.util.JsonUtil;
import com.zto.tbschedule.console.vo.BackTask;
import com.zto.tbschedule.console.vo.Task;
import com.zto.tbschedule.console.vo.TaskSchedule;
import com.zto.tbschedule.console.zookeeper.ZKManager;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
public class ScheduleServiceImpl implements IScheduleService {

    private static Logger logger = LoggerFactory.getLogger(ScheduleServiceImpl.class);
    private String BASE_TASK_TYPE = "baseTaskType";
    private String STRATEGY = "strategy";
    @Autowired
    private ApplicationModelMapper appMapper;
    @Autowired
    private ApplicationBackModelMapper backModelMapper;
    @Resource(name = "zkManager")
    private ZKManager zkManager;


    @Override
    public List<ScheduleTaskType> getScheduleTaskTypeListByAppId(Long id) {
        ApplicationModel model = appMapper.selectByPrimaryKey(id);
        String path = model.getZkPath() + "/" + BASE_TASK_TYPE;
        List<String> taskList = zkManager.getChildren(path);
        List<ScheduleTaskType> scheduleTaskTypeList = new ArrayList<ScheduleTaskType>();
        for (String task : taskList) {
            String taskJson = zkManager.getData(path + "/" + task);
            scheduleTaskTypeList.add(JsonUtil.parse(taskJson, ScheduleTaskType.class));
        }
        return scheduleTaskTypeList;
    }

    @Override
    public List<ScheduleStrategy> getScheduleStrategyListByTaskNameAndAppId(Long id, String taskName) {
        ApplicationModel model = appMapper.selectByPrimaryKey(id);
        String path = model.getZkPath() + "/" + STRATEGY;
        List<String> taskList = zkManager.getChildren(path);
        List<ScheduleStrategy> scheduleStrategyList = new ArrayList<ScheduleStrategy>();
        for (String strategy : taskList) {
            String taskJson = zkManager.getData(path + "/" + strategy);
            ScheduleStrategy scheduleStrategy = JsonUtil.parse(taskJson, ScheduleStrategy.class);
            if (scheduleStrategy.getTaskName().equals(taskName)) {
                scheduleStrategyList.add(scheduleStrategy);
            }
        }
        return scheduleStrategyList;
    }



    @Override
    public List<ScheduleServer> getScheduleServerListByTaskNameAndAppId(Long id, String taskName) {
        ApplicationModel model = appMapper.selectByPrimaryKey(id);
        String path = model.getZkPath() + "/" + BASE_TASK_TYPE + "/" + taskName + "/" + taskName + "/server";
        List<ScheduleServer> scheduleServerList = new ArrayList<ScheduleServer>();
        try {
            List<String> taskList = zkManager.getChildren(path);
            for (String server : taskList) {
                String taskJson = zkManager.getData(path + "/" + server);
                ScheduleServer scheduleServer = JsonUtil.parse(taskJson, ScheduleServer.class);
                //
                //开启服务立即启动:FetchDataCount=5,FetchDataNum=0,DealDataSucess=0,DealDataFail=0,DealSpendTime=0,otherCompareCount=0
                String dealInfoDesc = scheduleServer.getDealInfoDesc();
                if (dealInfoDesc != null) {
                    int index = dealInfoDesc.indexOf(":") + 1;
                    String[] dealInfoDescList = dealInfoDesc.substring(index).split(",");
                    for (String str : dealInfoDescList) {
                        String[] kv = str.split("=");
                        if (kv[0].equals("FetchDataCount")) {
                            scheduleServer.setFetchDataCount(kv[1]);
                        } else if (kv[0].equals("FetchDataNum")) {
                            scheduleServer.setFetchDataNum(kv[1]);
                        } else if (kv[0].equals("DealDataSucess")) {
                            scheduleServer.setDealDataSucess(kv[1]);
                        } else if (kv[0].equals("DealDataFail")) {
                            scheduleServer.setDealDataFail(kv[1]);
                        } else if (kv[0].equals("DealSpendTime")) {
                            scheduleServer.setDealSpendTime(kv[1]);
                        } else if (kv[0].equals("otherCompareCount")) {
                            scheduleServer.setOtherCompareCount(kv[1]);
                        }
                    }
                }
                scheduleServerList.add(scheduleServer);
            }
        } catch (Exception e) {
            logger.error("未找到" + taskName + "的运行信息");
        }

        return scheduleServerList;
    }

    @Override
    public List<ScheduleTaskItem> getScheduleTaskItemListByTaskNameAndAppId(Long appId, String taskName) {
        ApplicationModel model = appMapper.selectByPrimaryKey(appId);
        String path = model.getZkPath() + "/" + BASE_TASK_TYPE + "/" + taskName + "/" + taskName + "/taskItem";
        List<ScheduleTaskItem> scheduleTaskItemList = new ArrayList<ScheduleTaskItem>();
        try {
            List<String> taskList = zkManager.getChildren(path);
            for (String taskItem : taskList) {
                String cur_server = zkManager.getData(path + "/" + taskItem + "/cur_server");
                String deal_desc = zkManager.getData(path + "/" + taskItem + "/deal_desc");
                String parameter = zkManager.getData(path + "/" + taskItem + "/parameter");
                String req_server = zkManager.getData(path + "/" + taskItem + "/req_server");
                String sts = zkManager.getData(path + "/" + taskItem + "/sts");

                ScheduleTaskItem scheduleTaskItem = new ScheduleTaskItem();
                scheduleTaskItem.setBaseTaskType(taskName);
                scheduleTaskItem.setCurrentScheduleServer(cur_server);
                scheduleTaskItem.setDealDesc(deal_desc);
                scheduleTaskItem.setDealParameter(parameter);
                scheduleTaskItem.setRequestScheduleServer(req_server);
                scheduleTaskItem.setSts(sts);
                scheduleTaskItemList.add(scheduleTaskItem);
            }
        } catch (Exception e) {
            logger.error("未找到" + taskName + "的子任务运行信息");
        }

        return scheduleTaskItemList;
    }

    @Override
    public void editTaskSchedule(TaskSchedule taskSchedule) {
        ApplicationModel model = appMapper.selectByPrimaryKey(taskSchedule.getAppId());
        String path = model.getZkPath() + "/" + STRATEGY + "/" + taskSchedule.getStrategyName();
        ScheduleStrategy scheduleStrategy = new ScheduleStrategy();
        if ("Schedule".equals(taskSchedule.getKind())) {
            scheduleStrategy.setKind(ScheduleStrategy.Kind.Schedule);
        } else if ("Java".equals(taskSchedule.getKind())) {
            scheduleStrategy.setKind(ScheduleStrategy.Kind.Java);
        } else if ("Bean".equals(taskSchedule.getKind())) {
            scheduleStrategy.setKind(ScheduleStrategy.Kind.Bean);
        } else {
            throw new RuntimeException("非法的任务类型");
        }
        scheduleStrategy.setStrategyName(taskSchedule.getStrategyName());
        scheduleStrategy.setAssignNum(taskSchedule.getAssignNum());
        scheduleStrategy.setIPList(taskSchedule.getIpList() == null ? new String[]{"127.0.0.1"} : taskSchedule.getIpList().split(","));
        scheduleStrategy.setNumOfSingleServer(taskSchedule.getNumOfSingleServer());
        scheduleStrategy.setSts(taskSchedule.getSts() == null ? scheduleStrategy.STS_RESUME : taskSchedule.getSts());
        scheduleStrategy.setTaskName(taskSchedule.getTaskName());
        if (taskSchedule.getTaskParameter() != null) {
            String itemDefines = taskSchedule.getTaskParameter();
            itemDefines = itemDefines.replaceAll("\r", "");
            itemDefines = itemDefines.replaceAll("\n", "");
            itemDefines = itemDefines.replaceAll("\\[", "");
            itemDefines = itemDefines.replaceAll("\\]", "");
            itemDefines = itemDefines.replaceAll("\"", "");
            scheduleStrategy.setTaskParameter(itemDefines);
        }

        String valueString = JsonUtil.toJSON(scheduleStrategy);
        try {
            if (!zkManager.exists(path)) {
                zkManager.createData(path, valueString,model.getZkUsername(),model.getZkPassword(), CreateMode.PERSISTENT);
            } else {
                zkManager.uppData(path, valueString,getAutoStr(model));
            }
        } catch (Exception e) {
            throw new RuntimeException("ZK创建或者更新策略发生异常" + e.getMessage());
        }

    }


    @Override
    public void editTaskScheduleSts(TaskSchedule taskSchedule) {
        ApplicationModel model = appMapper.selectByPrimaryKey(taskSchedule.getAppId());
        String path = model.getZkPath() + "/" + STRATEGY + "/" + taskSchedule.getStrategyName();

        List<ScheduleStrategy> scheduleStrategyList = getScheduleStrategyListByTaskNameAndAppId(taskSchedule.getAppId(), taskSchedule.getTaskName());
        if (CollectionUtils.isEmpty(scheduleStrategyList)) {
            throw new RuntimeException("任务策略为空");
        }


        ScheduleStrategy scheduleStrategy = null;
        for (ScheduleStrategy strategy : scheduleStrategyList) {
            if (taskSchedule.getStrategyName().equals(strategy.getStrategyName())) {
                scheduleStrategy = strategy;
            }
        }

        if (scheduleStrategy == null) {
            throw new RuntimeException("未知的策略名称");
        }
        if ("pause".equals(taskSchedule.getSts())) {
            scheduleStrategy.setSts(ScheduleStrategy.STS_PAUSE);
        } else if ("resume".equals(taskSchedule.getSts())) {
            scheduleStrategy.setSts(ScheduleStrategy.STS_RESUME);
        } else {
            throw new RuntimeException("修改状态非法");
        }

        String valueString = JsonUtil.toJSON(scheduleStrategy);
        if (!zkManager.exists(path)) {
            throw new RuntimeException("修改的节点不存在");
        } else {
            try {
                zkManager.uppData(path, valueString,getAutoStr(model));
            } catch (Exception e) {
                throw new RuntimeException("ZK创建数据节点发生异常" + e.getMessage());
            }
        }
    }

    @Override
    public void delTaskSchedule(TaskSchedule taskSchedule) {
        ApplicationModel model = appMapper.selectByPrimaryKey(taskSchedule.getAppId());
        String path = model.getZkPath() + "/" + STRATEGY + "/" + taskSchedule.getStrategyName();
        if (!CollectionUtils.isEmpty(zkManager.getChildren(path))) {
            throw new RuntimeException("不能删除" + taskSchedule.getStrategyName() + "的运行策略，会导致必须重启整个应用才能停止失去控制的调度进程。" +
                    "可以先清空IP地址，等所有的调度器都停止后再删除调度策略");
        }
        if (!zkManager.exists(path)) {
            throw new RuntimeException("您要删除的节点不存在");
        } else {
            try {
                zkManager.delete(path,getAutoStr(model));
            } catch (Exception e) {
                throw new RuntimeException("ZK删除数据节点发生异常" + e.getMessage());
            }
        }
    }

    @Override
    public void editTask(Task task) {
        ApplicationModel model = appMapper.selectByPrimaryKey(task.getAppId());
        String path = model.getZkPath() + "/" + BASE_TASK_TYPE + "/" + task.getBaseTaskType();
        ScheduleTaskType taskType = new ScheduleTaskType();
        taskType.setBaseTaskType(task.getBaseTaskType());
        taskType.setDealBeanName(task.getDealBeanName());
        if (task.getHeartBeatRate() != 0) {
            taskType.setHeartBeatRate(task.getHeartBeatRate());
        }
        if (task.getJudgeDeadInterval() != 0) {
            taskType.setJudgeDeadInterval(task.getJudgeDeadInterval());
        }
        if (task.getThreadNumber() == 0) {
            taskType.setThreadNumber(task.getThreadNumber());
        }
        if (task.getFetchDataNumber() == 0) {
            taskType.setFetchDataNumber(task.getFetchDataNumber());
        }
        if (task.getExecuteNumber() == 0) {
            taskType.setExecuteNumber(task.getExecuteNumber());
        }
        if (task.getSleepTimeNoData() == 0) {
            taskType.setSleepTimeNoData(task.getSleepTimeNoData());
        }
        if (task.getSleepTimeInterval() == 0) {
            taskType.setSleepTimeInterval(task.getSleepTimeInterval());
        }
        if (task.getProcessorType() != null) {

            taskType.setProcessorType(task.getProcessorType());
        }
        if (task.getPermitRunStartTime() != null) {

            taskType.setPermitRunStartTime("null".equals(task.getPermitRunStartTime())?"":task.getPermitRunStartTime());
        }
        if (task.getPermitRunEndTime() != null) {

            taskType.setPermitRunEndTime("null".equals(task.getPermitRunEndTime())?"":task.getPermitRunEndTime());
        }
        if (task.getMaxTaskItemsOfOneThreadGroup() != 0) {
            taskType.setMaxTaskItemsOfOneThreadGroup(task.getMaxTaskItemsOfOneThreadGroup());
        }
        if (task.getTaskParameter() != null) {
            taskType.setTaskParameter(task.getTaskParameter());
        }
        if (task.getTaskItems() != null) {
            String itemDefines = task.getTaskItems();
            itemDefines = itemDefines.replaceAll("\r", "");
            itemDefines = itemDefines.replaceAll("\n", "");
            itemDefines = itemDefines.replaceAll("\\[", "");
            itemDefines = itemDefines.replaceAll("\\]", "");
            itemDefines = itemDefines.replaceAll("\"", "");
            taskType.setTaskItems(ScheduleTaskType.splitTaskItem(itemDefines));
        }
        if (task.getSts() != null) {
            task.setSts(task.getSts());
        }
        String valueString = JsonUtil.toJSON(taskType);
        try {
            if (!zkManager.exists(path)) {
                zkManager.createData(path, valueString,model.getZkUsername(),model.getZkPassword(), CreateMode.PERSISTENT);
            } else {
                zkManager.uppData(path, valueString,getAutoStr(model));
            }
        } catch (Exception e) {
            throw new RuntimeException("调度任务" + task.getBaseTaskType() + "创建或者更新失败",e);
        }

    }

    @Override
    public void clearTask(Task task) {
        ApplicationModel model = appMapper.selectByPrimaryKey(task.getAppId());
        String path = model.getZkPath() + "/" + BASE_TASK_TYPE + "/" + task.getBaseTaskType();
        List<String> pathList = zkManager.getChildren(path);
        for (String pathStr : pathList){
            zkManager.delete(path+"/"+pathStr,getAutoStr(model));
        }
    }

    @Override
    public void delTask(Task task) {
        ApplicationModel model = appMapper.selectByPrimaryKey(task.getAppId());
        String path = model.getZkPath() + "/" + BASE_TASK_TYPE + "/" + task.getBaseTaskType();
        zkManager.delete(path,getAutoStr(model));
    }

    @Override
    public void backupTask(Long appId) {
        ApplicationModel model = appMapper.selectByPrimaryKey(appId);
        String json = exportConfig(model.getZkPath());
        ApplicationBackModel backModel = new ApplicationBackModel();
        backModel.setAppId(appId);
        backModel.setBackData(json);
        backModel.setBackDate(new Date());
        backModel.setType(1);
        backModelMapper.insertSelective(backModel);
    }

    @Override
    public List<BackTask> searchBackupTask(Long appId) {
        ApplicationBackModelExample example = new ApplicationBackModelExample();
        example.createCriteria().andAppIdEqualTo(appId);
        List<ApplicationBackModel> backModelList =  backModelMapper.selectByExample(example);
        List<BackTask> backTaskList = new ArrayList<BackTask>();
        ApplicationModel app = appMapper.selectByPrimaryKey(appId);
        for(ApplicationBackModel model : backModelList){
            BackTask backTask  = new BackTask();
            backTask.setId(model.getId());
            backTask.setAppId(model.getAppId());
            backTask.setType(model.getType());
            backTask.setBackDate(model.getBackDate());
            backTask.setBackData(model.getBackData());
            backTask.setAppName(app != null ? app.getName() : "");
            backTaskList.add(backTask);
        }
        return backTaskList;
    }

    @Override
    public void delBackupTask(Long appId) {
        backModelMapper.deleteByPrimaryKey(appId);
    }

    @Override
    public void recoveryBackupTask(Long id) {
        if(id!=null){
            ApplicationBackModel model = backModelMapper.selectByPrimaryKey(id);
            ApplicationModel appModel = appMapper.selectByPrimaryKey(id);
            List<ConfigNode> configNodeList = JsonUtil.parseArray(model.getBackData(),ConfigNode.class);
            if(!CollectionUtils.isEmpty(configNodeList)){
                for (ConfigNode node: configNodeList){
                    String path = node.getRootPath() + "/"
                            + node.getConfigType()+"/"+node.getName();
                    if(zkManager.exists(path)){
                        zkManager.uppData(path,node.getValue(),getAutoStr(appModel));
                    }else{
                        zkManager.createData(path,node.getValue(),appModel.getZkUsername(),appModel.getZkPassword(),CreateMode.PERSISTENT);
                    }
                }
            }
        }
    }

    private String getAutoStr(ApplicationModel appModel) {
        return appModel.getZkUsername()+":"+appModel.getZkPassword();
    }


    private String exportConfig(String rootPath){
        List<ConfigNode> configNodeList = new ArrayList<ConfigNode>();
        for (String type : new String[] {BASE_TASK_TYPE, STRATEGY}) {
            String bTTypePath = rootPath + "/" + type;
            List<String> fNodeList = zkManager.getChildren(bTTypePath);
            for (int i = 0; i < fNodeList.size(); i++) {
                String fNode = fNodeList.get(i);
                ConfigNode configNode = new ConfigNode(rootPath, type, fNode);
                configNode.setValue(new String(zkManager.getData(bTTypePath + "/" + fNode)));
                configNodeList.add(configNode);
            }
        }
        return JsonUtil.toJSON(configNodeList);
    }

}
